use std::{collections::HashSet, time::Instant};
use winit::{keyboard::KeyCode, event::ElementState};
use getset::{CloneGetters, CopyGetters, Getters, MutGetters, Setters, WithSetters};

// general key data
#[derive(PartialEq)]
pub enum KeyStateRaw {
    Pressed,
    Released,
}

impl KeyStateRaw {
    pub fn is_pressed(&self) -> bool {
        return *self == KeyStateRaw::Pressed;
    }
}

impl Default for KeyStateRaw {
    fn default() -> Self {
        return Self::Released;
    }
}

impl From<ElementState> for KeyStateRaw {
    fn from(item: ElementState) -> Self {
        match item {
            ElementState::Pressed => {
                return KeyStateRaw::Pressed;
            }
            ElementState::Released => {
                return KeyStateRaw::Released;
            }
        }
    }
}

#[derive(PartialEq, Default, Getters, Setters, WithSetters, MutGetters, CopyGetters, CloneGetters)]
pub struct KeyState {
    #[getset(get = "pub", set = "pub")]
    state: KeyStateRaw,

    #[getset(get = "pub", set = "pub")]
    time: Option<Instant>,
}

impl KeyState {
    pub fn is_pressed(&self) -> bool {
        return self.state.is_pressed();
    }
    pub fn is_released(&self) -> bool {
        return !self.is_pressed();
    }    
}

impl From<KeyStateRaw> for KeyState {
    fn from(item: KeyStateRaw) -> Self {
        KeyState { state: item, time: None }
    }
}

#[derive(PartialEq, Default, Getters, Setters, WithSetters, MutGetters, CopyGetters, CloneGetters)]
pub struct KeyStates {
    #[getset(get = "pub", set = "pub")]
    move_left_state: KeyState,

    #[getset(get = "pub", set = "pub")]
    move_right_state: KeyState,

    #[getset(get = "pub", set = "pub")]
    move_forward_state: KeyState,

    #[getset(get = "pub", set = "pub")]
    move_backward_state: KeyState,

    #[getset(get = "pub", set = "pub")]
    move_up_state: KeyState,

    #[getset(get = "pub", set = "pub")]
    move_down_state: KeyState,

    #[getset(get = "pub", set = "pub")]
    look_left_state: KeyState,

    #[getset(get = "pub", set = "pub")]
    look_right_state: KeyState,

    #[getset(get = "pub", set = "pub")]
    look_up_state: KeyState,

    #[getset(get = "pub", set = "pub")]
    look_down_state: KeyState,
}

#[derive(PartialEq, Getters, Setters, WithSetters, MutGetters, CopyGetters, CloneGetters)]
pub struct KeyMappings {
    // move mapping
    #[getset(get = "pub")]
    move_left: KeyCode,

    #[getset(get = "pub")]
    move_right: KeyCode,

    #[getset(get = "pub")]
    move_forward: KeyCode,

    #[getset(get = "pub")]
    move_backward: KeyCode,

    #[getset(get = "pub")]
    move_up: KeyCode,

    #[getset(get = "pub")]
    move_down: KeyCode,

    #[getset(get = "pub")]
    look_left: KeyCode,

    #[getset(get = "pub")]
    look_right: KeyCode,

    #[getset(get = "pub")]
    look_up: KeyCode,

    #[getset(get = "pub")]
    look_down: KeyCode,

    // ctrl mapping
    #[getset(get = "pub")]
    exit: KeyCode,

}

impl Default for KeyMappings {
    fn default() -> Self {
        return Self {
            move_left: KeyCode::KeyA,
            move_right: KeyCode::KeyD,
            move_forward: KeyCode::KeyW,
            move_backward: KeyCode::KeyS,
            move_up: KeyCode::KeyE,
            move_down: KeyCode::KeyQ,
            look_left: KeyCode::ArrowLeft,
            look_right: KeyCode::ArrowRight,
            look_up: KeyCode::ArrowUp,
            look_down: KeyCode::ArrowDown,
            // 
            exit: KeyCode::Escape,
        };
    }
}
